package chapter07._05_Logging;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

/**
 * @Author: insight
 * @Description: 高级日志的学习 1.日志级别 2.设置消息级别 3.记录异常
 * @LastDate: 2020/11/4
 */
public class Test02_Advanced {
    /**
     * 寻找自己的日志记录器 如果没有这个名字 就创建以此命名的记录器
     * public static Logger getLogger(String name);
     * 由于没有被引用的变量 可能会被JVM回收 为了避免 要用static修饰
     * 因为静态变量的生命周期是整个运行周期 程序结束才会被回收
     * 此方法会设置本地化消息存放在名为resourceBundleName的资源包中
     * public static Logger getLogger(String name, String resourceBundleName);
     */
    private static final Logger logger = Logger.getLogger("chapter07._05_Logging.Test02_Advanced");

    /**
     * 日志有7个级别 从高到低分别是
     * SEVERE 十分严重
     * WARNING 警告
     * INFO 普通信息
     * CONFIG
     * FINE
     * FINER
     * FINEST
     * 默认级别是INFO 也就是记录INFO及以上级别的信息
     * 因此INFO以下的级别信息 应该用于记录测试/诊断 对用户作用不大的信息
     * 如果要修改默认级别 需要修改日志配置文件 默认设置会抑制INFO以下级别的信息
     */
    public static void mySetLevel() {

        //logger.setLevel(Level.FINEST);//手动设置为fine级别 也就是记录FINE及以上级别的信息
        logger.setLevel(Level.FINEST);
        //也可以这样写
        //使用各级别的方法
        //logger.warning("一个警告");
        //logger.finer("较好的信息");
        //或者在打印时 设置消息的级别
        //logger.log(Level.CONFIG, "配置信息");
    }

    /**
    * 一般来说 log会打印调用的类和方法
    * 但是如果虚拟机进行了优化 可能就得不到具体信息
    * 此时可以使用logp来获得具体信息
    * */
    public static void getSpecificInformation() {
        logger.logp(Level.FINEST, "Test02_Advanced", "getSpecificInformation", "call logp method");
    }

    /**
     * 跟踪执行流的日志方法
     * public void entering(String sourceClass, String sourceMethod)
     * public void entering(String sourceClass, String sourceMethod, Object param1)
     * public void entering(String sourceClass, String sourceMethod, Object params[]) 可能重写为可变参数
     *
     * public void exiting(String sourceClass, String sourceMethod)
     * public void exiting(String sourceClass, String sourceMethod, Object result)
     *
     * 这些方法会生成FINER级别且以字符串"Enter""Return"开头的日志
     * 底层也是调用logp
     * 在这里不打印的原因是底层logp打印的是finer级别的 此时默认配置是info 修改配置即可
     */
    public static int followExecuteStream() {
        int cnt = 0;
        logger.entering("Test02_Advanced", "getSpecificInformation");
        //execute something ...
        logger.exiting("Test02_Advanced", "getSpecificInformation");
        return cnt;
    }

    /**
     * 另外一个常用之处是打印异常
     * 常用两个方法
     * public void throwing(String sourceClass, String sourceMethod, Throwable thrown)
     * 源码: if (!isLoggable(Level.FINER)) return; 也就是说只打印FINER级别信息
     * public void log(Level level, String msg, Throwable thrown)
     * */
    public static void logThrowable() {
        logger.throwing("Test02_Advanced", "getSpecificInformation", new IOException());
        logger.log(Level.WARNING, "Exception in Here", new IOException());
    }

    public static void updateLoggerConfig() {
        /*
        * 一、日志配置文件默认位于
        * 1. java9之前 比如jre1.8.0_161\lib\logging.properties
        * 2. java9之后 比如jdk11.0.8\conf\logging.properties
        *
        * 二、更换配置文件 需要修改启动参数
        * -Djava.util.logging.config.file=configfile mainclass
        * 或
        * LogManager.getLogManager().readConfiguration("cfgFileName");//无参就选择默认的配置文件
        * 或
        * public void updateConfiguration(Function<String, BiFunction<String,String,String>> mapper)
        * updateConfiguration有两种选择
        * 1. 优先选择新值
        * key -> ((oldValue, newValue) -> newValue != null ? newValue : oldValue)
        * 2. 只想更新以xxx比如这个类名字开头的键
        * key -> key.startsWith("chapter07._05_Logging.Test02_Advanced") ? (oldValue, newValue) -> newValue : (oldValue, newValue) -> oldValue
        *
        * 三、修改全局默认日志级别
        * 更新此行 .level = INFO
        *
        * 四、指定自定义的日志记录器的级别
        * chapter07._05_Logging.Test02_Advanced.level=FINE
        * 或者
        * logger.setLevel(Level.FINEST);
        *
        * 不过即使设置了也可能看不到 控制台也有日志级别
        * 需要进行另外设置
        * java.util.logging.ConsoleHandler.level=FINE
        * 或 安装自己的记录器
        * logger.setUseParentHandlers(false);
        * //一个日志记录器会把记录发送到自己类的处理器 和 祖先处理器
        * //祖先日志记录器会把所有高于等于INFO的记录发送到控制台
        * //不禁用祖先日志记录器会看到双重记录
        * new ConsoleHandle().setLevel(Level.INFO);
        * logger.addHandler(handler);
        * */
    }

    public static void main(String[] args) throws IOException {
//        LogManager.getLogManager().readConfiguration();
//        LogManager.getLogManager().updateConfiguration();
        Test02_Advanced.mySetLevel();
//        Test02_Advanced.getSpecificInformation();
//        Test02_Advanced.followExecuteStream();
        Test02_Advanced.logThrowable();

    }
}
